import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import java.rmi.RMISecurityManager;
import java.rmi.Naming;

public class MandelbrotClient extends JFrame implements MouseListener,
		MouseMotionListener {

	static final long serialVersionUID = 28461893476L;

	private static final int TAMANHO_X = 640;	private static final int TAMANHO_Y = 480;	private Vetor2D posicaoFractal;
	private Vetor2D posicaoJanela;

	private Image offscreen;

	private boolean janelaZoom = true;

	private double zoom;
	private double fatorZoom;
	private int py;

	private java.util.Set servidores;

	/**
	 * Constroi aplicacao mandelbrot
	 */
	public MandelbrotClient() {

		super("Fractal Mandelbrot");
		setBounds(0,0,TAMANHO_X, TAMANHO_Y);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(false);

		offscreen = new BufferedImage(TAMANHO_X, TAMANHO_Y, BufferedImage.TYPE_INT_RGB);

		posicaoFractal = new Vetor2D(-0.8, 0);
		posicaoJanela = new Vetor2D(TAMANHO_X / 2, TAMANHO_Y / 2);

		zoom = TAMANHO_X * 0.125296875;
		fatorZoom = 2.178;
		addMouseListener(this);
		addMouseMotionListener(this);

		servidores = new java.util.HashSet();
	}

	/**
	 * Metodo de inicio
	 * @param args Argumentos linha de comando
	 */
	public static void main(String [] args) {

		// install RMI security manager
		System.setSecurityManager(new RMISecurityManager());

		// arg. 0 = name of server
		if (args.length < 1) {
			System.err.println("Uso: MandelbrotClient [<server-rmi-url> [<server-rmi-url> [...]]]");
			System.exit(-1);
		}

		MandelbrotClient cliente = new MandelbrotClient();

		// look up in nameserver
		for (int c = 0; c < args.length; c++) {
			String fullname = args[c];
			MandelbrotServer server = null;

			try {
				server = (MandelbrotServer)Naming.lookup(fullname);
				cliente.adicionarServidor(server);
			} catch (Exception e) {
				System.out.println("Caught an exception doing name lookup on "+fullname
    	                    +": "+e);
				System.exit(-1);
			}
		}

		cliente.setVisible(true);
		cliente.desenharFractal();
	}

	/**
	 * Recalcula imagem do fractal e desenha double buffer
	 */
	public void desenharFractal() {

		Graphics g = offscreen.getGraphics();

		int c = 0;
		for (java.util.Iterator it = servidores.iterator(); it.hasNext();) {
			MandelbrotServer server = (MandelbrotServer)it.next();

			new Thread(
				new MandelbrotRenderer(TAMANHO_X, TAMANHO_Y, (TAMANHO_Y/servidores.size())*c,
				TAMANHO_Y/servidores.size(), posicaoFractal, zoom, g, server)
				).start();

			c++;
		}
		repaint();
	}

	/**
	 * Pinta double buffer na saida grafica e desenha o retangulo de zoom
	 */
	public void paint(Graphics g) {

		g.drawImage(offscreen, 0, 0, this);

		/* Desenha retangulo de zoom */
		if (janelaZoom) {
			g.setColor(new Color(0xFFFF00));
			g.drawRect((int) (posicaoJanela.x - ((TAMANHO_X/2) / fatorZoom)),
					(int) (posicaoJanela.y - ((TAMANHO_Y/2) / fatorZoom)),
					(int) (2.0f * ((TAMANHO_X/2) / fatorZoom)),
					(int) (2.0f * ((TAMANHO_Y/2) / fatorZoom)));
		}
	}

	/**
	 * Metodo chamado no evento de clique do mouse. Efetua zoom in ou out
	 * dependendo do botao
	 */
	public void mouseClicked(MouseEvent e) {

		if (e.getButton() == MouseEvent.BUTTON1) {
			posicaoFractal.x += ((posicaoJanela.x - (TAMANHO_X/2)) / zoom);
			posicaoFractal.y += ((posicaoJanela.y - (TAMANHO_Y/2)) / zoom);
			zoom *= fatorZoom;
		} else if (e.getButton() == MouseEvent.BUTTON3) {
			posicaoFractal.x += ((((TAMANHO_X/2) - posicaoJanela.x) / zoom) * fatorZoom);
			posicaoFractal.y += ((((TAMANHO_Y/2) - posicaoJanela.y) / zoom) * fatorZoom);
			zoom /= fatorZoom;

		}
		else if (e.getButton() == MouseEvent.BUTTON2) {
			posicaoFractal.x = -0.8;
			posicaoFractal.y = 0;
			zoom = TAMANHO_X * 0.125296875;			
		}

		desenharFractal();
	}

	/**
	 * Adiciona servidor ao cliente
	 */
	public void adicionarServidor(MandelbrotServer server) {
		servidores.add(server);
	}

	/**
	 * Quando o mouse entra na area do applet
	 */
	public void mouseEntered(MouseEvent e) {
		janelaZoom = true;
	}

	/**
	 * Quando o mouse sai da area do applet
	 */
	public void mouseExited(MouseEvent e) {
		janelaZoom = false;
		
		repaint();
	}

	/**
	 * Metodo nao utilizado
	 */
	public void mousePressed(MouseEvent e) {

	}

	/**
	 * Metodo nao utilizado
	 */
	public void mouseReleased(MouseEvent e) {

	}

	/**
	 * Metodo chamado no evento de arrastar do mouse. causa o redimensionamento
	 * do retangulo de zoom
	 */
	public void mouseDragged(MouseEvent e) {

		if (py > e.getY()) {
			fatorZoom *= 0.98f;
		} else if (py < e.getY()) {
			fatorZoom *= 1.02f;
		}

		py = e.getY();

		repaint();
	}

	/**
	 * Metodo chamado no evento de movimento do mouse. Reposiciona o retangulo
	 * de zoom.
	 */
	public void mouseMoved(MouseEvent e) {
		posicaoJanela.x = e.getX();
		py = e.getY();
		posicaoJanela.y = e.getY();

		repaint();
	}
}
